package com.nulldev.util.web.HttpClient.util;

import java.util.List;
import java.util.Map;
import java.util.Set;

import com.nulldev.util.JVM.JVM;
import com.nulldev.util.JVM.reflections.Reflections;
import com.nulldev.util.VariableAPI.MathUtil;
import com.nulldev.util.data.Variables;
import com.nulldev.util.io.FastIO.FastIO;
import com.nulldev.util.web.HttpClient.HttpClientFlags;
import com.nulldev.util.web.HttpClient.HttpRequest;
import com.nulldev.util.web.HttpClient.HttpResponse;

public class HttpClientUtil {
	private static boolean hasALPN, __has_alpn_init = false;

	public static boolean hasALPN() {
		if (!__has_alpn_init) {
			try {
				final Reflections r = Reflections.use("javax.net.ssl.SSLParameters");
				final Set<String> methods = r.methods();
				__has_alpn_init = true;
				return (hasALPN = (methods.contains("setApplicationProtocols") && methods.contains("getApplicationProtocols")));
			} catch (Exception ex) {
				JVM.errorln(ex);
				return JVM.version() >= 1.8f;
			}
		} else
			return hasALPN;
	}

	public static boolean isSuccessfulRequest(final int responseCode) {
		/*
		 * this.conn.get().getResponseCode() == 404 || this.conn.get().getResponseCode()
		 * == 410
		 */
		switch (responseCode) {
			case 400:
			case 401:
			case 404:
			case 410:
			case 500:
			case 503:
				return false;
			default:
				return true;
		}
	}

	private static boolean __has_encoding(final String str) {
		if (str == null)
			return false;
		switch (str) {
			case "gzip":
			case "br":
			case "deflate":
				return true;
			default:
				return false;
		}
	}

	private static String __get_header(final String name, final Map<String, List<String>> headers) {
		if (!headers.containsKey(name))
			return null;
		final List<String> set = headers.get(name);
		if (set.size() != 1) {
			/* TODO: The fuck should we be doing here? */
			return null;
		} else {
			return set.get(0);
		}
	}

	public static <T> long getRawFallbackLength(final HttpResponse<T> resp) {
		final Map<String, List<String>> headers = resp.headers();
		return MathUtil.safeParseL(__get_header("Content-Length", headers), -1L);
	}

	public static <T> long getFallbackLength(final HttpResponse<T> resp) {
		final Map<String, List<String>> headers = resp.headers();
		final String compression;
		if (headers.containsKey("Content-Encoding")) {
			compression = __get_header("Content-Encoding", headers);
		} else if (headers.containsKey("Transfer-Encoding")) {
			compression = __get_header("Transfer-Encoding", headers);
		} else {
			compression = null;
		}
		if (__has_encoding(compression)) {
			/* Not possible to find out the uncompressed content length. */
			return -1L;
		} else {
			return MathUtil.safeParseL(__get_header("Content-Length", headers), -1L);
		}
	}

	public static void printRequest(final HttpRequest<?> result) {
		Variables.requireNonNull(result, "result");
		if (!result.isFeatureFlagSupported(HttpClientFlags.FEATURE_FLAG_REQUEST_READ_API))
			return;
		JVM.println(result.url());
		final Map<String, List<String>> lines = result.headers();
		for (final Map.Entry<String, List<String>> s : lines.entrySet()) {
			FastIO.get().println("\t" + s.getKey() + ": " + s.getValue());
		}
	}

	public static void printResponse(final HttpResponse<?> result) {
		Variables.requireNonNull(result, "result");
		JVM.println(result.status() + " " + result.transportVersion());
		final Map<String, List<String>> lines = result.headers();
		for (final Map.Entry<String, List<String>> s : lines.entrySet()) {
			FastIO.get().println("\t" + s.getKey() + ": " + s.getValue());
		}
	}
}
